//========================================================================
// *作者：海盗猫  主页：ilplay.com
// *脚本：EditorInspectorListEelment
// *描述：
// *?2021 MYJL . All rights reserved.
//* ======================================================================
using System;
using HDMCode.UIFrame;
using UnityEditor;
using UnityEngine;

namespace HDMCode.UIFrameEditor
{
    [CustomPropertyDrawer(typeof(UIComponentElement), true)]
    public class EditorInspectorListEelment : PropertyDrawer
    {
        public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
        {
            //获取绑定对象
            SerializedProperty targetSp = property.FindPropertyRelative("target");

            //获取组件链表
            SerializedProperty componentListSp = property.FindPropertyRelative("componentList");

            if (RemoveNulls(componentListSp))
            {
                componentListSp.serializedObject.ApplyModifiedPropertiesWithoutUndo();
                return;
            }

            EditorGUI.BeginProperty(position, label, property);
            {
                position = EditorGUI.PrefixLabel(position, GUIUtility.GetControlID(FocusType.Passive), label);
                EditorGUILayout guiLayour = new EditorGUILayout(position, position.width);

                int oldIndent = EditorGUI.indentLevel;
                EditorGUI.indentLevel = 0;
                {
                    GUI.Button(guiLayour.IndexRect, componentListSp.arraySize.ToString());
                    //绘制列表对象
                    EditorGUI.BeginChangeCheck();
                    {
                        EditorGUI.PropertyField(guiLayour.TargetRect, targetSp, GUIContent.none);
                        if (EditorGUI.EndChangeCheck())
                        {
                            componentListSp.ClearArray();
                            targetSp.serializedObject.ApplyModifiedProperties();
                            componentListSp.serializedObject.ApplyModifiedProperties();
                        }
                    }

                    //绘制列表组件
                    bool isExsistTarget = targetSp.objectReferenceValue != null;
                    using (new EditorGUI.DisabledScope(!isExsistTarget))
                    {
                        if (isExsistTarget)
                        {
                            GameObject target = targetSp.objectReferenceValue as GameObject;
                            if (target)
                            {
                                Component[] existComps = target.GetComponents<Component>();

                                //按钮（铺在下方）
                                GUIContent guiContent = new GUIContent();
                                guiContent.text = (componentListSp.arraySize == 0) ? "无" : string.Empty; //按钮文本


                                if (GUI.Button(guiLayour.ComponentsRect, guiContent, EditorStyles.popup))
                                {
                                    BuildPopupList(existComps, componentListSp).DropDown(guiLayour.ComponentsRect);
                                }


                                //图标列表（覆盖在上方）
                                int posIndex = 0;
                                for (int i = 0; i < existComps.Length; i++) //用它遍历能够保证组件在Inspector上的顺序
                                {
                                    Component comp = existComps[i];

                                    int savedIndex = GetIndexFromSavedComponentList(componentListSp, comp); //只显示已保存的组件
                                    if (savedIndex >= 0)
                                    {
                                        Texture icon = GetIconBy(comp.GetType());
                                        DrawIcon(guiLayour.ComponentsRect, posIndex, icon);
                                        posIndex++;
                                    }
                                }
                            }
                        }
                        else
                        {
                            //按钮（纯占位）
                            if (GUI.Button(guiLayour.ComponentsRect, "无", EditorStyles.popup)) { }
                        }
                    }
                }
                EditorGUI.indentLevel = oldIndent;
            }
            EditorGUI.EndProperty();
        }

        /// <summary>
        /// 组件选择方法
        /// </summary>
        /// <param name="existComps"></param>
        /// <param name="componentListSp"></param>
        /// <returns></returns>
        private GenericMenu BuildPopupList(Component[] existComps, SerializedProperty componentListSp)
        {
            GenericMenu menu = new GenericMenu();

            foreach (Component comp in existComps)
            {
                int savedIndex = GetIndexFromSavedComponentList(componentListSp, comp);

                menu.AddItem(new GUIContent(comp.GetType().Name), savedIndex >= 0, (source) =>
                {
                    //点击Item时，若Item已存在执行移除，否则执行添加。
                    if (savedIndex >= 0)
                    {
                        //注意，删除元素前必须先将其置为null，
                        //否则直接调用DeleteArrayElementAtIndex会使元素变为null而不是从列表中移除。
                        componentListSp.GetArrayElementAtIndex(savedIndex).objectReferenceValue = null;
                        componentListSp.DeleteArrayElementAtIndex(savedIndex);
                    }
                    else
                    {
                        componentListSp.InsertArrayElementAtIndex(componentListSp.arraySize);
                        componentListSp.GetArrayElementAtIndex(componentListSp.arraySize - 1).objectReferenceValue = source as Component;
                    }
                    componentListSp.serializedObject.ApplyModifiedProperties();
                    EditorApplication.RepaintHierarchyWindow(); //需要强刷Hierarchy
                }, comp);
            }

            return menu;
        }


        /// <summary>
        /// 删除空对象组件
        /// </summary>
        /// <param name="componentListSp"></param>
        /// <returns></returns>
        private bool RemoveNulls(SerializedProperty componentListSp)
        {
            bool hasNull = false;
            for (int i = componentListSp.arraySize - 1; i >= 0; i--)
            {
                if (componentListSp.GetArrayElementAtIndex(i).objectReferenceValue == null)
                {
                    componentListSp.DeleteArrayElementAtIndex(i);
                    hasNull = true;
                }
            }
            return hasNull;
        }


        /// <summary>
        /// 组件在已保存组件列表中的位置
        /// </summary>
        /// <param name="componentListSp"></param>
        /// <param name="comp"></param>
        /// <returns></returns>
        private int GetIndexFromSavedComponentList(SerializedProperty componentListSp, Component comp)
        {
            int index = -1;
            for (int i = 0; i < componentListSp.arraySize; i++)
            {
                Component savedComp = componentListSp.GetArrayElementAtIndex(i).objectReferenceValue as Component;
                if (savedComp && savedComp.Equals(comp))
                {
                    index = i;
                    break;
                }
            }
            return index;
        }

        /// <summary>
        /// 绘制图标
        /// </summary>
        /// <param name="selectRect"></param>
        /// <param name="posIndex"></param>
        /// <param name="icon"></param>
        static private void DrawIcon(Rect selectRect, int posIndex, Texture icon)
        {
            float iconWidth = EditorGUIUtility.singleLineHeight * 0.8f;
            float iconHeight = iconWidth;
            float leftPadding = 5;
            float iconSpacing = 5;

            float iconX = selectRect.x + leftPadding + (iconWidth + iconSpacing) * posIndex;  //水平居左
            float iconY = selectRect.y + (selectRect.height - iconHeight) / 2;  //竖直居中

            Rect iconRect = new Rect(iconX, iconY, iconWidth, iconHeight);

            GUI.DrawTexture(iconRect, icon);
        }


        /// <summary>
        /// 获取图标
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        static public Texture GetIconBy(Type type)
        {
            //系统内置图标
            Texture systemIcon = EditorGUIUtility.ObjectContent(null, type).image;
            //TMP 三个组件的图标
            //if (type == typeof(TMPro.TMP_InputField))
            //{
            //    customIcon = (Texture2D)EditorGUIUtility.Load("Packages/com.unity.textmeshpro/Editor Resources/Gizmos/TMP - Input Field Icon.psd");
            //}
            //else if (type == typeof(TMPro.TMP_Dropdown))
            //{
            //    customIcon = (Texture2D)EditorGUIUtility.Load("Packages/com.unity.textmeshpro/Editor Resources/Gizmos/TMP - Dropdown Icon.psd");
            //}
            //else if (type == typeof(TMPro.TextMeshProUGUI))
            //{
            //    customIcon = (Texture2D)EditorGUIUtility.Load("Packages/com.unity.textmeshpro/Editor Resources/Gizmos/TMP - Text Component Icon.psd");
            //}

            //todo其他自定义图标自行添加

            //默认图标
            Texture csScriptIcon = EditorGUIUtility.IconContent("cs Script Icon").image;

            return systemIcon ?? csScriptIcon;
        }
    }

}


